package com.lagou.study.config;

import com.alibaba.druid.pool.DruidAbstractDataSource;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.lagou.study.Annotation.DemoAnnotaion;
import com.lagou.study.util.SpringContextUtil;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.ChildData;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.ServletContext;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

public class ZkConfig {
    private final static String CONNECTSTRING = "127.0.0.1:2181";
    private static final String CONFIG_PREFIX = "/druid";
    public static CuratorFramework curatorFramework = null;
    //充当缓存
    private Map<String, String> cache = new HashMap<>();

    //初始化zookeeper连接
    public static synchronized CuratorFramework getInstance() {
        if (curatorFramework == null) {
            curatorFramework = CuratorFrameworkFactory.builder()
                    .connectString(CONNECTSTRING)
                    .sessionTimeoutMs(1000)
                    .connectionTimeoutMs(1000)
                    .retryPolicy(new ExponentialBackoffRetry(1000, 1000))
                    .build();
            curatorFramework.start();
        }
        return curatorFramework;
    }

    public ZkConfig() {
        this.curatorFramework = ZkConfig.getInstance();
        this.init();
    }

    //监听配置
    public void init() {
        try {
            //获取连接
            curatorFramework = ZkConfig.getInstance();
            //获取CONFIG_PREFIX的子节点 并将数据保存到缓存中
            curatorFramework.getChildren().forPath(CONFIG_PREFIX).stream().forEach(k -> {
                try {
                    String value = new String(curatorFramework.getData().forPath(CONFIG_PREFIX + "/" + k));
                    cache.put(k, value);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });

            //绑定一个监听 cacheData设为true 当事件发生后可以拿到节点发送的内容
            //使该配置文件的每个应用机器都需要监听  这里只用于演示
            PathChildrenCache pathChildrenCache = new PathChildrenCache(curatorFramework, CONFIG_PREFIX, true);
            //添加监听
            pathChildrenCache.getListenable().addListener((curatorFramework1, pathChildrenCacheEvent) -> {
                ChildData childData = pathChildrenCacheEvent.getData();
                if (childData != null) {
                    String path = childData.getPath();
                    //判断节点是否以制定开头开始
                    if (path.startsWith(CONFIG_PREFIX)) {
                        String key = path.replace(CONFIG_PREFIX + "/", "");
                        switch (pathChildrenCacheEvent.getType()) {
                            case CHILD_ADDED:
                            case CHILD_UPDATED:   //添加节点或者修改节点数据时   修改缓存数据
                                cache.put(key, new String(pathChildrenCacheEvent.getData().getData()));
                                System.out.println("我要变了！！！！！！！！！！！！！！！");
                                DruidDataSource dataSource = (DruidDataSource)SpringContextUtil.getBean("dataSource");
                                dataSource.setDriverClassName(getCacheConfig("driver-class-name"));
                                dataSource.setUrl(getCacheConfig("url"));
                                dataSource.setUsername(getCacheConfig("username"));
                                dataSource.setPassword(getCacheConfig("password"));
                                dataSource.restart();
                                break;
                            case CHILD_REMOVED:  //节点删除时  从缓存中删除数据
                                cache.remove(key);
                                break;
                        }
                        if (PathChildrenCacheEvent.Type.CHILD_ADDED.equals(pathChildrenCacheEvent.getType()) ||
                                PathChildrenCacheEvent.Type.CHILD_UPDATED.equals(pathChildrenCacheEvent.getType())) {
                            cache.put(key, new String(pathChildrenCacheEvent.getData().getData()));
                        }
                        // 子节点被删除时 从缓存中删除
                        if (PathChildrenCacheEvent.Type.CHILD_REMOVED.equals(pathChildrenCacheEvent.getType())) {
                            cache.remove(key);
                        }
                    }
                }
            });
            //启动监听
            pathChildrenCache.start(PathChildrenCache.StartMode.POST_INITIALIZED_EVENT);//POST_INITIALIZED_EVENT模式 会刷新缓存
        } catch (Exception e) {

        }
    }

    //保存配置信息
    public void save(String name, String value) throws Exception {
        curatorFramework = ZkConfig.getInstance();
        String path = CONFIG_PREFIX + "/" + name;
        //判断节点是否存在 如果不存在就创建
        Stat stat = curatorFramework.checkExists().forPath(path);
        if (stat == null) //如果不存在该节点就创建
            curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath(path);

        curatorFramework.setData().forPath(path, value.getBytes());
        //缓存中存入数据
        cache.put(name, value);

    }

    //获取配置信息
    public String getCacheConfig(String name) {
        return cache.get(name);
    }
}
